﻿using jvm.instructions.common;
using jvm.native.java.lang;
using jvm.rtda;
using jvm.rtda.frame;
using jvm.rtda.heap.clazz.method;
using jvm.rtda.heap.pool;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace jvm.instructions.references
{
    class ATHROW : NoOperandsInstruction
    {
        public override void Execute(JFrame frame)
        {
            // throw(new Exception())，参数压栈后调用athrow
            JObject exceptionObject = frame.operandStack.PopRef();
            if (exceptionObject == null)
            {
                Console.WriteLine("java.lang.NullPointerException");
                Environment.Exit(0);
            }
            JThread thread = frame.thread;
            if (!FindAndGotoExceptionHandler(thread, exceptionObject))
            {
                HandleUncaughtException(thread, exceptionObject);
            }
        }

        public bool FindAndGotoExceptionHandler(JThread thread, JObject exceptionObject)
        {
            while (!thread.IsEmpty())
            {
                JFrame frame = thread.CurrentFrame();
                int pc = frame.nextPc;
                int handlerPc = frame.method.FindExceptionHandler(frame.method.jClass, pc - 1);
                if (handlerPc > 0)
                {
                    JOperandStack stack = frame.operandStack;
                    stack.Clear();
                    stack.PushRef(exceptionObject);
                    frame.nextPc = handlerPc;
                    return true;
                }
                thread.PopFrame();
            }
            return false;
        }

        void HandleUncaughtException(JThread thread, JObject exceptionObject)
        {
            thread.ClearStack();
            JObject detailMessage = exceptionObject.GetRefVar("detailMessage", "Ljava/lang/String;");
            string msg = StringPool.String(detailMessage);
            Console.WriteLine(exceptionObject.jClass.JavaName + ":" + msg);
            StackTraceElement[] elements = (StackTraceElement[])exceptionObject.exceptionInfo;
            foreach (StackTraceElement element in elements)
            {
                Console.WriteLine("\tat" + element.ToString());
            }
        }
    }
}
